#pragma once
#include "../Common/Net.hpp"
#include "../Common/Message.hpp"
#include "../Common/Detail.hpp"
#include "../Common/Fileds.hpp"
#include "../Common/Abstract.hpp"
#include <future>

namespace zgwrpc
{
    namespace client
    {

        // 保存的请求id与请求描述的映射
        class Requestor
        {
        public:
            using ptr = std::shared_ptr<Requestor>;
            using RequestCallback = std::function<void(const BaseMessage::ptr &)>; // 请求回调函数
            using AsyncResponse = std::future<BaseMessage::ptr>;                   // 异步响应

            // Request描述类
            struct RequestDescribe
            {
                using ptr = std::shared_ptr<RequestDescribe>;
                BaseMessage::ptr request;
                Rtype rtype;
                std::promise<BaseMessage::ptr> response;
                RequestCallback callback;

                // void SetCallback(RequestCallback callback){callback = callback;}
                // void SetResponse(BaseMessage::ptr response){ response = response;}
                // void SetRtype(Rtype rtype){ rtype = rtype;}
                // AsyncResponse GetAsyncResponse() { return response.get_future(); }
            };

            // 拿到响应
            //当创建请求描述之后，再进行发送消息，当收到请求时，会异步调用回调函数
            void OnMessage(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg)
            {
                LOG(LogLevel::DEBUG) << "接收到服务端信息";
                std::string rid = msg->rid();
                cout << "rid:" << rid << endl;
                RequestDescribe::ptr describe = GetDescribe(rid);// 根据rid获取请求描述
                if (describe.get() == nullptr)
                {
                    LOG(LogLevel::ERROR) << " 请求描述不存在";
                    return;
                }
                if (describe->rtype == Rtype::REQ_ASYNC) //根据请求类型来处理是返回值还是回调
                {
                    describe->response.set_value(msg);
                }
                else if (describe->rtype == Rtype::REQ_CALLBACK)
                {
                    describe->callback(msg);
                }
                else
                {
                    LOG(LogLevel::ERROR) << " 请求类型未知";
                }
                DelDescribe(rid);
            }

            // 异步
            bool Send(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg, AsyncResponse &async_rsp)
            {
                RequestDescribe::ptr describe = newDescribe(msg, Rtype::REQ_ASYNC, nullptr);
                if (describe.get() == nullptr)
                {
                    LOG(LogLevel::ERROR) << " 创建请求描述失败";
                    return false;
                }
                conn->send(msg);
                async_rsp = describe->response.get_future();
                return true;
            }

            // 同步
            bool Send(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg, BaseMessage::ptr &rsp)
            {
                AsyncResponse future_rsp;
                bool ret = Send(conn, msg, future_rsp);
                if (ret == false)
                {
                    return false;
                }
                rsp = future_rsp.get();
                return true;
            }

            // 回调
            bool Send(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg, RequestCallback &callback)
            {
                RequestDescribe::ptr describe = newDescribe(msg, Rtype::REQ_CALLBACK, callback);
                if (describe.get() == nullptr)
                {
                    LOG(LogLevel::ERROR) << " 创建请求描述失败";
                    return false;
                }
                conn->send(msg);
                return true;
            }

        private:
            // 根据rid生成请求描述类
            RequestDescribe::ptr newDescribe(const BaseMessage::ptr &msg, Rtype rtype, RequestCallback callback)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                RequestDescribe::ptr describe = std::make_shared<RequestDescribe>();
                describe->request = msg;
                describe->rtype = rtype;
                if (rtype == Rtype::REQ_CALLBACK && callback != nullptr)
                {
                    describe->callback = callback;
                }

                _request_desc.insert(std::make_pair(msg->rid(), describe));
                return describe;
            }
            RequestDescribe::ptr GetDescribe(const std::string &rid)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _request_desc.find(rid);
                if (it == _request_desc.end())
                {
                    return nullptr;
                }
                return it->second;
            }

            void DelDescribe(const std::string &rid)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _request_desc.erase(rid);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, RequestDescribe::ptr> _request_desc;//根据rid创建请求描述
        };
    }
}